package main

import (
	"bufio"
	"crypto/md5"
	"fmt"
	"io"
	"os"
	"path/filepath"
	"sort"
)

type searchResult struct {
	//文件全路径
	absoluteName [200]string
	// 被引用统计
	count uint32
	// 文件名
	name string
	//所有同名统计
	totalCount uint32
}

//文件被引用统计，key为文件名(绝对路径)，value为被引用次数
var fileContents = make(map[string]searchResult, 10000)

var ch = make(chan int, 512)
var debug = false
var autoDelete = false

// 查看查找结果
func showResult(searchPath string) {
	var totalRef = 0
	var keys []string

	for k := range fileContents {
		keys = append(keys, k)
	}
	sort.Strings(keys)

	fmt.Printf("\n\n文件md5冲突统计\n----------------------\n")
	totalRef = 0
	for _, k := range keys {
		var i uint32
		file := fileContents[k]
		if file.totalCount > 1 {
			fmt.Printf("%-30s count: %d\n", k, file.totalCount)
			for i = 0; i < file.totalCount; i++ {
				tempObj := file.absoluteName[i]
				totalRef++
				//是否自动删除
				if autoDelete {
					err := os.Remove(tempObj)
					errStr := "删除成功"
					if err != nil {
						errStr = "删除失败"
					}
					fmt.Printf("\t%-30s [%s]\n", tempObj, errStr)
				} else {
					fmt.Printf("\t%-30s\n", tempObj)
				}
			}
		}
	}
	fmt.Printf("所有md5冲突文件总数: %d\n", totalRef)
}

func findFile(path string) {
	var pathArray [100]string
	var count = 0
	var fileCount = 0
	filepath.Walk(path, func(path string, info os.FileInfo, err error) error {
		if err != nil {
		}
		//find text
		if !info.IsDir() {
			fileCount++
			// fmt.Printf("%200s %d bytes\n", info.Name(), info.Size())
			if info.Size() < 1024*1024*10 {
				pathArray[count] = path
				count++
				//每一百个执行任务
				if count >= 100 {
					count = 0
					go findText(pathArray[0:100])
					<-ch
				}
			}
		}
		return nil
	})
	//确保所有文件处理完成
	go findText(pathArray[0:count])
	<-ch

	fmt.Printf("总共有 %d 个文件\n", fileCount)

}

// 在指定文件集合中，查找指定内容是否出现
func findText(paths []string) {
	for _, path := range paths {
		md5Value, err := md5SumFile(path)
		if err != nil {
			fmt.Println(err.Error())
		}
		temp := fileContents[md5Value]
		count := temp.totalCount
		temp.absoluteName[count] = path
		temp.totalCount++
		fileContents[md5Value] = temp
		if debug {
			fmt.Println(path, md5Value)
		}

	}
	ch <- 1
}

func md5SumFile(file string) (string, error) {
	f, err := os.Open(file)
	if err != nil {
		return "", err
	}
	defer f.Close()
	r := bufio.NewReader(f)

	h := md5.New()

	_, err = io.Copy(h, r)
	if err != nil {
		return "", err
	}

	return fmt.Sprintf("%x", h.Sum(nil)), nil

}

func main() {
	args := os.Args
	if len(args) < 2 {
		fmt.Println("请输入 搜索路径")
		return
	}
	path := args[1]

	_, err := os.Stat(path)

	if err != nil {
		fmt.Println("该路径不存在")
	} else {
		findFile(path)
		showResult(path)
	}
}
